package nape.geom;
import nape.geom.AABB;
import nape.geom.Mat23;
import nape.geom.Vec2;
import nape.geom.VecMath;
import nape.util.FastMath;
import nape.util.MixPool;
import nape.util.Names;
import nape.util.NpAlgorithm;
import nape.util.NpList;
import nape.util.NpNode_ZNContact;
import nape.util.NpAllocList_ZNContact;
import nape.util.NpNode_ZNV2;
import nape.util.NpList_ZNV2;
import nape.util.NpNode_Vec2__Dynamic;
import nape.util.NpList_Vec2__Dynamic;
import nape.util.NpNode_ZNShp;
import nape.util.NpList_ZNShp;







    class ImmutableAxisList {
        public var znp_inner:ZNAxis;
        public var znp_validate:Void->Void;
        public var length(get_length,never):Int;
        
        
        
        public function new(inner:ZNAxis,validate:Void->Void) {
            znp_inner = inner;
            znp_validate = validate;
        }
        
        public inline function get_length() {
            znp_validate();
            return znp_inner.size();
        }
        
        public inline function at(i:Int) {
            if(i<0||i>=length) return null;            
            else {
                znp_validate();
                return  znp_inner.at(length-1-i).wrapper();
            }
        }
    }


class Axis {
    public var znp_inner:ZNAxis;
    
    public function new(inner:ZNAxis) {
        znp_inner = inner;
        inner.outer = this;
    }
    
    public var localNormal(get_localNormal,never):Vec2;
    public inline function get_localNormal() {
        if(znp_inner.wrap_localNormal==null) {
            znp_inner.wrap_localNormal = new Vec2(0,0);
                { znp_inner.wrap_localNormal.znp_inner.x = znp_inner.localNormalx; znp_inner.wrap_localNormal.znp_inner.y = znp_inner.localNormaly; };
        }
        return znp_inner.wrap_localNormal;
    }
    
    public var projection(get_projection,never):Float;
    public inline function get_projection() {
        return znp_inner.projection;
    }
}

class ZNAxis {
    public var outer:Axis;
    
    
    public var next:ZNAxis;
    public inline function elem ():ZNAxis return this
    public inline function begin():ZNAxis return next 
    
    public inline function _setbeg(i:ZNAxis) next=i
    public inline function _new   (o:ZNAxis):ZNAxis return o
    public inline function _delete(i:ZNAxis) {}
    public inline function _delelt(o:ZNAxis) {}
    public inline function _clear ( ) return false
    
    
    
    public inline function add(o:ZNAxis) {
        var temp = _new(o);
        temp.next = begin();
        _setbeg(temp);
    }
    
    
    public inline function addAll(x:ZNAxis) {
           {
    var npiterator = x.begin();
    while(npiterator != null) {
        var i = npiterator.elem();
        {
            
            
            add(i);
        }
        npiterator = npiterator.next;
    }
};
    }
    
    
    public inline function insert(cur:ZNAxis,o:ZNAxis) {
        if(cur==null) { add(o); return begin(); }
        else {
            var temp = _new(o);
            temp.next = cur.next;
            cur.next = temp;
            return temp;
        }
    }
    
    
    
    
    public inline function pop():Void {
        var ret = begin();
        _setbeg(ret.next);
        _delelt(ret.elem());
        _delete(ret);
    }
    
    
    public inline function pop_unsafe():ZNAxis {
        var ret = front();
        pop();
        return ret;
    }
    
    
    
    
    public inline function remove(obj:ZNAxis):Bool {
        var pre = null;
        var cur = begin();
        var ret = false;
        while(cur!=null) {
            if(cur.elem()==obj) {
                erase(pre,cur);
                ret = true;
                break;
            }
            pre = cur;
            cur = cur.next;
        }
        return ret;
    }
    
    
    public inline function erase(pre:ZNAxis,cur:ZNAxis):ZNAxis {
        var old = cur; cur = cur.next;
        if(pre==null) _setbeg(cur);
        else pre.next = cur;
        _delelt(old.elem());
        _delete(old);
        return cur;
    }
    
    
    public inline function splice(pre:ZNAxis,cur:ZNAxis,n:Int):ZNAxis {
        while(n-->0 && cur!=null) cur = erase(pre,cur);
        return cur;
    }
    
    
    public inline function clear() {
        if(_clear()) {
            while(!empty()) {
                var old = begin();
                _setbeg(old.next);
                _delelt(old.elem());
                _delete(old);
            }
        }
    }
    
    
    
    
    public inline function reverse() {
        var cur = begin();
        var pre = null;
        while(cur!=null) {
            var nx = cur.next;
            cur.next = pre;
            _setbeg(cur);
            pre = cur;
            cur = nx;
        }
    }
    
    
    
    
    public inline function empty():Bool return begin()==null
    
    
    public inline function size() {
        var cnt = 0;
        var cur = begin();
        while(cur!=null) { cnt++; cur = cur.next; }
        return cnt;
    }
    
    
    public inline function has(obj:ZNAxis) return  ({
    var ret = false;
      {
    var npiterator = this.begin();
    while(npiterator != null) {
        var npite = npiterator.elem();
        {
            
            
            {
        if(npite==obj) {
            ret = true;
            break;
        }
    };
        }
        npiterator = npiterator.next;
    }
};
    ret;
})
    
    
    
    
    public inline function front() return begin().elem()
    
    
    public inline function back() {
        var ret = begin();
        var cur = ret;
        while(cur!=null) { ret = cur; cur = cur.next; }
        return ret.elem();
    }
    
    
    public inline function iterator_at(ind:Int) {
        var ret = begin();
        while(ind-->0 && ret!=null) ret = ret.next;
        return ret;
    }
    
    
    public inline function at(ind:Int) {
        var it = iterator_at(ind);
        return if(it!=null) it.elem() else null;
    }
    


    
     public var localNormalx:Float; public var localNormaly:Float; public var wrap_localNormal:Vec2;
     public var worldNormalx:Float; public var worldNormaly:Float;
    
    
    public var projection:Float;
    
    
    public var edgeLength:Float;
    
    public function new() {}
    
    public inline function wrapper() {
        if(outer==null) outer = new Axis(this);
        return outer;
    }
    
    public inline function clone() {
        var ret = new ZNAxis();
            { ret.localNormalx = localNormalx; ret.localNormaly = localNormaly; };
            { ret.worldNormalx = worldNormalx; ret.worldNormaly = worldNormaly; };
        ret.projection = projection;
        ret.edgeLength = edgeLength;
        return ret;
    }
}
